import { Injectable } from "@nestjs/common";
import { ConfigService } from '@nestjs/config';
import { CozeAPI, RoleType } from '@coze/api';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Conversation, Message } from '@app/entities';


export type ChatMessage = {
  role: 'user' | 'assistant' | 'system';
  content: string;
};


@Injectable()
export class CozeService {
  private translateClient: CozeAPI;
  private frontMatterClient: CozeAPI;
  private defaultBotIds: { translate: string; frontMatter: string };

  constructor(
    private readonly config: ConfigService,
    @InjectRepository(Conversation) private readonly convRepo: Repository<Conversation>,
    @InjectRepository(Message) private readonly msgRepo: Repository<Message>,
  ) {
    const coze = this.config.get<any>('coze');
    if (!coze) {
      throw new Error('Coze config not loaded. Ensure coze.config.ts is added to ConfigModule.load');
    }

    const translateCfg = coze.translate;
    const frontMatterCfg = coze.frontMatter;

    this.translateClient = new CozeAPI({
      token: translateCfg.COZE_API_KEY,
      baseURL: translateCfg.COZE_BASE_URL,
    });

    this.frontMatterClient = new CozeAPI({
      token: frontMatterCfg.COZE_API_KEY,
      baseURL: frontMatterCfg.COZE_BASE_URL,
    });

    this.defaultBotIds = {
      translate: translateCfg.COZE_BOT_ID,
      frontMatter: frontMatterCfg.COZE_BOT_ID,
    };
  }

  private async ensureConversation(botId: string, userId?: number, title?: string) {
    // 简单策略：按 userId+botId 查找最近一条活跃会话，没有则创建
    let conv = await this.convRepo.findOne({ where: { userId, botId }, order: { createdAt: 'DESC' } as any });
    if (!conv) {
      conv = this.convRepo.create({
        title: title || '对话',
        status: 'active' as any,
        userId: userId ?? null,
        cozeConversationId: '',
        botId,
        botType: botId === this.defaultBotIds.frontMatter ? ('front_matter' as any) : ('translate' as any),
        region: 'zh',
        metadata: {},
        messageCount: 0,
        lastActiveAt: new Date(),
      });
      conv = await this.convRepo.save(conv);
    }
    return conv;
  }

  private async saveMessages(conversationId: string, cozeMessages: any[]) {
    const entities: Message[] = [];
    for (const m of cozeMessages || []) {
      const rawRole = (m.role?.toLowerCase?.() || 'user');
      const role = (rawRole === 'tool') ? 'assistant' : rawRole;
      entities.push(this.msgRepo.create({
        conversationId,
        cozeMessageId: m.id,
        role: role as any,
        type: this.normalizeMessageType(m.type, role),
        content: String(m.content ?? ''),
        status: this.normalizeMessageStatus(m.status),
        metadata: m.meta_data || null,
        usage: m.usage ? {
          promptTokens: m.usage.prompt_tokens,
          completionTokens: m.usage.completion_tokens,
          totalTokens: m.usage.total_tokens,
        } : null,
        completedAt: new Date(),
      }));
    }
    if (entities.length) {
      await this.msgRepo.save(entities);
      await this.convRepo.update({ id: conversationId }, { messageCount: () => 'messageCount + ' + entities.length, lastActiveAt: new Date() } as any);
    }
  }

  private mapRole(role: ChatMessage['role']): RoleType {
    switch (role) {
      case 'assistant':
        return RoleType.Assistant;
      case 'system':
        return RoleType.User;
      default:
        return RoleType.User;
    }
  }

  private normalizeMessageType(input: string | undefined, role: string | undefined): any {
    const allowed = new Set(['text', 'image', 'file', 'object_string', 'function_call', 'tool_output']);
    const v = (input || '').toLowerCase();
    // 将 'answer' 统一归一为 'text'，避免数据库枚举不一致导致的截断
    if (v === 'answer') return 'text' as any;
    return allowed.has(v) ? (v as any) : ('text' as any);
  }

  private normalizeMessageStatus(input: string | undefined): any {
    const allowed = new Set(['pending', 'completed', 'failed']);
    const v = (input || '').toLowerCase();
    return allowed.has(v) ? (v as any) : ('completed' as any);
  }

  async translate(text: string, lang?: string, userId?: number) {
    const prompt = lang
      ? `请将以下内容翻译成${lang}：\n\n${text}`
      : `请翻译以下内容：\n\n${text}`;

    const conv = await this.ensureConversation(this.defaultBotIds.translate, userId, '翻译');
    const v = await this.translateClient.chat.createAndPoll({
      bot_id: this.defaultBotIds.translate,
      additional_messages: [
        { role: RoleType.User, content: prompt, content_type: 'text' },
      ],
    });

    await this.saveMessages(conv.id, v.messages);
    const answer = v.messages?.filter(m => m.role === RoleType.Assistant).map(m => m.content).join('\n') ?? '';
    return {
      status: v.chat.status,
      usage: v.chat.usage,
      answer,
      messages: v.messages,
    };
  }

  async frontMatter(content: string, userId?: number) {
    const systemHint = `你是一个 FrontMatter 提取助手。\n\n请从给定正文中提取文章前置元数据并以 JSON 返回，字段尽量包含：title, description, tags(array), category, date(ISO8601), cover(optional)。只返回 JSON，不要包含其它说明。`;

    const conv = await this.ensureConversation(this.defaultBotIds.frontMatter, userId, 'FrontMatter');
    const v = await this.frontMatterClient.chat.createAndPoll({
      bot_id: this.defaultBotIds.frontMatter,
      additional_messages: [
        { role: RoleType.User, content: systemHint, content_type: 'text' },
        { role: RoleType.User, content, content_type: 'text' },
      ],
    });

    await this.saveMessages(conv.id, v.messages);
    const answer = v.messages?.filter(m => m.role === RoleType.Assistant).map(m => m.content).join('\n') ?? '';
    let json: any = null;
    try { json = JSON.parse(answer); } catch { }

    return {
      status: v.chat.status,
      usage: v.chat.usage,
      raw: answer,
      parsed: json,
      messages: v.messages,
    };
  }

  async chat(botId: string, messages: ChatMessage[], userId?: number) {
    const conv = await this.ensureConversation(botId, userId, '对话');
    const v = await this.translateClient.chat.createAndPoll({
      bot_id: botId,
      additional_messages: messages.map(m => ({
        role: this.mapRole(m.role),
        content: m.content,
        content_type: 'text',
      })),
    });

    await this.saveMessages(conv.id, v.messages);
    return v;
  }

  async stream(botId: string, messages: ChatMessage[]) {
    return this.translateClient.chat.stream({
      bot_id: botId,
      additional_messages: messages.map(m => ({
        role: this.mapRole(m.role),
        content: m.content,
        content_type: 'text',
      })),
    });
  }

  async health() {
    return { ok: true };
  }
  async createWsChat(botId: string) {
    // 使用 translateClient 的 WS 能力建立到 Coze 的直连
    const ws = await this.translateClient.websockets.chat.create({ bot_id: botId });
    return ws;
  }

}